
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;

public class ManualLabeledMasses implements ActionListener, ListSelectionListener
{
	IPWindow window;
	JFrame frame;
	JPanel mainPane;
	JPanel visPanel;
	JList massList;

	/**
	 * Feature data text fields.
	 * Each entry holds 3 text fields.
	 * - 1 for value
	 * - 1 for certainty
	 * - 1 for importance
	 * Keys:
	 * "area"
	 * "average_grey"
	 * "variance_grey"
	 * "boundary_length"
	 * "sharpness"
	 * "thinness"
	 */
	HashMap<String, Vector<JTextField>> featureTextFields;

	public ManualLabeledMasses(IPWindow _window)
	{
		window = _window;
		Color bgColor = new Color(255,255,255);
		
		//// Create our frame, panel and buttons.
		frame = new JFrame("Labeled Masses");
		mainPane = new JPanel(new BorderLayout());

		//// Populate panel
		mainPane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));

		//// Action panel
		JPanel actionPanel = new JPanel();
		actionPanel.setBorder(
				BorderFactory.createCompoundBorder(
					BorderFactory.createTitledBorder("  "),
					BorderFactory.createEmptyBorder(5,5,5,5)
					));
		actionPanel.setBackground(bgColor);
		JButton btnFindMasses = new JButton("Find Labeled Masses");
		btnFindMasses.setActionCommand("find");
		btnFindMasses.addActionListener(this);
		actionPanel.add(btnFindMasses);

		//// Found masses pannel
		JPanel massesPanel = new JPanel();
		massesPanel.setBorder(
				BorderFactory.createCompoundBorder(
					BorderFactory.createTitledBorder("Found Masses"),
					BorderFactory.createEmptyBorder(5,5,5,5)
					));

		// Create empty vertical list
		massList = new JList();
		massList.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
		massList.setLayoutOrientation(JList.VERTICAL);
		massList.addListSelectionListener(this);

		JScrollPane listScroller = new JScrollPane(massList);
		listScroller.setPreferredSize(new Dimension(250, 80));
		listScroller.setAlignmentX(Component.LEFT_ALIGNMENT);

		massesPanel.add(listScroller);

		//// Visualization Panel
		visPanel = new JPanel();
		visPanel.setBorder(
		BorderFactory.createCompoundBorder(
			BorderFactory.createTitledBorder("Visualization"),
			BorderFactory.createEmptyBorder(5, 5, 5, 5)
			));
		visPanel.add(new JLabel("new test"));
		//visPanel.setLayout(new BoxLayout(centerPanel,
		//            BoxLayout.PAGE_AXIS));


		//// Output panel (Extracted Mass Features)
		JPanel outputPanel = createMassFeaturesPanel(bgColor);
		
		//// Center panel (masses and output)
		JPanel centerPanel = new JPanel();
		centerPanel.setLayout(new BoxLayout(centerPanel,
					BoxLayout.PAGE_AXIS));
		centerPanel.add(massesPanel);
		centerPanel.add(outputPanel);
		centerPanel.add(visPanel);



		//// Nav buttons
		JPanel navPane = new JPanel();
		JButton b1 = new JButton("Prev");
		JButton b2 = new JButton("Save/Visualize");
		JButton b3 = new JButton("Finish");
		b1.setActionCommand("prev");
		b2.setActionCommand("save");
		b3.setActionCommand("finish");
		b1.addActionListener(this);
		b2.addActionListener(this);
		b3.addActionListener(this);
		navPane.add(b1);
		navPane.add(b2);
		navPane.add(b3);
		navPane.setBackground(bgColor);

		mainPane.add(actionPanel, BorderLayout.PAGE_START);
		mainPane.add(centerPanel, BorderLayout.CENTER);
		mainPane.add(navPane, BorderLayout.PAGE_END);
		
		//// Set panel as mane pane on frame, and show frame.
		frame.setContentPane(mainPane);
		mainPane.setOpaque(true);
		mainPane.setBackground(bgColor);
		frame.pack();
		//frame.setLocationRelativeTo(window.frame);
		frame.setVisible(true);		


		////
		// Warning messges
		if (window.getROI() == null)
		{
			p.print("Warning: ROI is null.  Verfiy image is loaded.");
		}
		else if (window.getROI().getLabeledImage() == null)
		{
			p.print("Warning: Labeled image is null. Verfiy " +
					"mass detection was performed in previous step");
		}
	}

	void updateVisualPanel(Mass mass)
	{
		visPanel.removeAll();
		MassVis massvis = window.getMassVis(mass.getMassID());
		if (massvis == null) return;
		visPanel.add(new JLabel("Area", massvis.getAreaIcon(), JLabel.CENTER));
		visPanel.add(new JLabel("Thin", massvis.getThinIcon(), JLabel.LEFT));
		visPanel.add(new JLabel("Sharpness", massvis.getSharpIcon(), JLabel.RIGHT));
		visPanel.add(new JLabel("Grey", massvis.getGreyIcon(), JLabel.RIGHT));
		visPanel.updateUI();
	}

	public void actionPerformed(ActionEvent e)
	{
		String cmd = e.getActionCommand();
		if (cmd.equals("find"))
		{
			p.print("Finding labeled masses");
			
			window.getROI().doFindLabeledMasses();
			window.updateFrame();
			updateMassList(window.getROI().getMasses());
		}
		else if (cmd.equals("prev"))
		{
			new ManualMassDetect(window);
			frame.dispose();
		}
		else if (cmd.equals("save"))
		{
			saveMassFeatureChanges(getSelectedMass());
			//call the method to generate the visual Icons
			//associated with features	
			window.generate_Mass_Visuals();
			updateVisualPanel(getSelectedMass());
			p.print("Changes saved.");
		}
		else if (cmd.equals("finish"))
		{	
			frame.dispose();
		}
	}

	// Setup Mass Feature Panel
	private JPanel createMassFeaturesPanel(Color bgColor)
	{
		JPanel panel = new JPanel();
		panel.setBorder(
				BorderFactory.createCompoundBorder(
					BorderFactory.createTitledBorder("Extracted Mass Features"),
					BorderFactory.createEmptyBorder(5,5,5,5)
					));

		panel.setLayout(new GridLayout(0, 5));

		// Add panel header
		panel.add(new JLabel("Feature"));
		panel.add(new JLabel("Value"));
		panel.add(new JLabel("Normalized Value"));
		panel.add(new JLabel("Certainty"));
		panel.add(new JLabel("Importance"));

		// Create feature text field map
		featureTextFields = new HashMap<String, Vector<JTextField>>();

		String [] keys = {
			"area",
			"average_grey",
			"variance_grey",
			"boundary_length",
			"sharpness",
			"thinness"
		};
		for (String key : keys)
		{
			// Add 3 fields for each key
			Vector<JTextField> tfields = new Vector<JTextField>();
			tfields.add(new JTextField(5)); // value
			tfields.add(new JTextField(5)); // normalized_value
			tfields.add(new JTextField(5)); // certainty
			tfields.add(new JTextField(5)); // importance
			featureTextFields.put(key, tfields);

			// Add key and fields to panel
			panel.add(new JLabel(key));
			panel.add(tfields.elementAt(0));
			panel.add(tfields.elementAt(1));
			panel.add(tfields.elementAt(2));
			panel.add(tfields.elementAt(3));

			// Set value to readonly
			tfields.elementAt(0).setEditable(false);
			tfields.elementAt(1).setEditable(false);
		}

		panel.setBackground(bgColor);

		return panel;
	}

	// Update JList
	private void updateMassList(Vector<Mass> masses)
	{
		massList.setListData(masses);
	}

	public Mass getSelectedMass()
	{
		int index = massList.getSelectedIndex();
		//p.print("Selected: " + index);
		ROI roi = window.getROI();
		if (roi != null)
		{
			return roi.getMasses().elementAt(index);
		}
		else
		{
			return null;
		}
	}

	public void valueChanged(ListSelectionEvent e)
	{
		if (!massList.getValueIsAdjusting())
		{
			Mass mass = getSelectedMass();
			displayMassFeatures(mass);
			updateVisualPanel(mass);

			// Modify and show colored mass.
			int massid = mass.getMassID();
			ImageData newImg = window.colorMassPixels(massid);
			window.roi.setVisualizedImage(newImg);
			window.frame.setImageState(4);  // 4 == visualized image
		}
	}

	public void displayMassFeatures(Mass mass)
	{
		Vector<JTextField> tfields;

		if (mass == null)
		{
			p.print("Invalid mass");
			return;
		}

		try {
			String[] fieldNames = {"Area", "Average_Grey", "Variance_Grey", "Boundary_Length", "Sharpness", "thinness"};
			for (String fieldName : fieldNames) {
				tfields = featureTextFields.get(fieldName.toLowerCase());
				Feature feature = ((Feature)Mass.class.getField(fieldName).get(mass));
				tfields.elementAt(0).setText(Float.toString(feature.value));
				tfields.elementAt(1).setText(Float.toString(feature.normalized_value));
				tfields.elementAt(2).setText(Float.toString(feature.certainty));
				tfields.elementAt(3).setText(Float.toString(feature.importance));
			}
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void saveMassFeatureChanges(Mass mass)
	{
		Vector<JTextField> tfields;

		if (mass == null)
		{
			p.print("Invalid mass");
			return;
		}
		String[] fieldNames = {"Area", "Average_Grey", "Variance_Grey", "Boundary_Length", "Sharpness", "thinness"};
		for (String fieldName: fieldNames) {
			tfields = featureTextFields.get(fieldName.toLowerCase());
			try {
				((Feature) Mass.class.getField(fieldName).get(mass)).value = Float.parseFloat(tfields.elementAt(0).getText());
				((Feature) Mass.class.getField(fieldName).get(mass)).certainty = Float.parseFloat(tfields.elementAt(2).getText());
				((Feature) Mass.class.getField(fieldName).get(mass)).importance = Float.parseFloat(tfields.elementAt(3).getText());
			} catch (NumberFormatException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (SecurityException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NoSuchFieldException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}
